{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "_jQ1tEQCxwRx"
   },
   "source": [
    "##### Copyright 2021.7.24 by K同学啊@CSDN."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "rF2x3qooyBTI"
   },
   "source": [
    "# 深度卷积生成对抗网络（DCGAN）"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 一、前言"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "🔥本文 GitHub [https://github.com/kzbkzb/Python-AI](https://github.com/kzbkzb/Python-AI) 已收录\n",
    "\n",
    "- 作者：[K同学啊](https://mp.weixin.qq.com/s/NES9RhtAhbX_jsmGua28dA)\n",
    "- 来自专栏：《深度学习100例》-Tensorflow2版本\n",
    "\n",
    "我的环境：\n",
    "\n",
    "- 语言环境：Python3.6.5\n",
    "- 编译器：jupyter notebook\n",
    "- 深度学习环境：TensorFlow2.4.1"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "🚀 **深度学习新人必看：**\n",
    "\n",
    "1. [小白入门深度学习 | 第一篇：配置深度学习环境](https://mtyjkh.blog.csdn.net/article/details/118575238)\n",
    "2. [小白入门深度学习 | 第二篇：编译器的使用-Jupyter Notebook](https://mtyjkh.blog.csdn.net/article/details/118814364)\n",
    "3. [小白入门深度学习 | 第三篇：深度学习初体验](https://mtyjkh.blog.csdn.net/article/details/119081309)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 二、什么是生成对抗网络？"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "2MbKJY38Puy9"
   },
   "source": [
    "生成对抗网络（GAN）是当今计算机科学领域最有趣的想法之一。两个模型通过对抗过程同时训练。一个生成器模型（“艺术家”）学习创造看起来真实的图像，而判别器模型（“艺术评论家”）学习区分真假图像。\n",
    "\n",
    "\n",
    "![](./pic_gif/MINST_DCGAN_19.gif)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "GAN 的应用十分广泛，它的应用包括图像合成、风格迁移、照片修复以及照片编辑，数据增强等等。\n",
    "\n",
    "**1）风格迁移**\n",
    "\n",
    "图像风格迁移是将图像A的风格转换到图像B中去，得到新的图像。\n",
    "\n",
    "![image.png](./pictures/18-1.png)\n",
    "\n",
    "**2）图像生成**\n",
    "\n",
    "GAN 不但能生成人脸，还能生成其他类型的图片，比如漫画人物。\n",
    "\n",
    "![image.png](./pictures/18-2.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "e1_Y75QXJS6h"
   },
   "source": [
    "### 1. 设置GPU"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2020-09-22T22:01:26.408716Z",
     "iopub.status.busy": "2020-09-22T22:01:26.408062Z",
     "iopub.status.idle": "2020-09-22T22:01:32.650022Z",
     "shell.execute_reply": "2020-09-22T22:01:32.649284Z"
    },
    "id": "WZKbyU2-AiY-"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[PhysicalDevice(name='/physical_device:GPU:0', device_type='GPU')]\n"
     ]
    }
   ],
   "source": [
    "import tensorflow as tf\n",
    "\n",
    "gpus = tf.config.list_physical_devices(\"GPU\")\n",
    "\n",
    "if gpus:\n",
    "    tf.config.experimental.set_memory_growth(gpus[0], True)  #设置GPU显存用量按需使用\n",
    "    tf.config.set_visible_devices([gpus[0]],\"GPU\")\n",
    "    \n",
    "# 打印显卡信息，确认GPU可用\n",
    "print(gpus)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2020-09-22T22:01:34.012326Z",
     "iopub.status.busy": "2020-09-22T22:01:34.011660Z",
     "iopub.status.idle": "2020-09-22T22:01:34.185780Z",
     "shell.execute_reply": "2020-09-22T22:01:34.185175Z"
    },
    "id": "YfIk2es3hJEd"
   },
   "outputs": [],
   "source": [
    "from tensorflow.keras  import layers\n",
    "from IPython           import display\n",
    "import matplotlib.pyplot as plt\n",
    "import numpy             as np\n",
    "import glob,imageio,os,PIL,time"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "iYn4MdZnKCey"
   },
   "source": [
    "### 2. 加载和准备数据集\n",
    "\n",
    "您将使用 MNIST 数据集来训练生成器和判别器。生成器将生成类似于 MNIST 数据集的手写数字。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2020-09-22T22:01:34.509071Z",
     "iopub.status.busy": "2020-09-22T22:01:34.508345Z",
     "iopub.status.idle": "2020-09-22T22:01:34.635470Z",
     "shell.execute_reply": "2020-09-22T22:01:34.634847Z"
    },
    "id": "NFC2ghIdiZYE"
   },
   "outputs": [],
   "source": [
    "(train_images, _), (_, _) = tf.keras.datasets.mnist.load_data()\n",
    "\n",
    "train_images = train_images.reshape(train_images.shape[0], 28, 28, 1).astype('float32')\n",
    "\n",
    "# 将图片标准化到 [-1, 1] 区间内\n",
    "train_images = train_images / 127.5 - 1  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2020-09-22T22:01:34.639738Z",
     "iopub.status.busy": "2020-09-22T22:01:34.639056Z",
     "iopub.status.idle": "2020-09-22T22:01:34.641553Z",
     "shell.execute_reply": "2020-09-22T22:01:34.641058Z"
    },
    "id": "S4PIDhoDLbsZ"
   },
   "outputs": [],
   "source": [
    "BUFFER_SIZE = 60000\n",
    "BATCH_SIZE  = 256\n",
    "\n",
    "# 批量化和打乱数据\n",
    "train_dataset = tf.data.Dataset.from_tensor_slices(train_images).shuffle(BUFFER_SIZE).batch(BATCH_SIZE)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "THY-sZMiQ4UV"
   },
   "source": [
    "## 三、创建模型"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "-tEyxE-GMC48"
   },
   "source": [
    "### 1. 生成器\n",
    "\n",
    "生成器使用 `tf.keras.layers.Conv2DTranspose` （上采样）层来从种子（随机噪声）中产生图片。以一个使用该种子作为输入的 `Dense` 层开始，然后多次上采样直到达到所期望的 28x28x1 的图片尺寸。注意除了输出层使用 tanh 之外，其他每层均使用 `tf.keras.layers.LeakyReLU` 作为激活函数。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2020-09-22T22:01:36.223758Z",
     "iopub.status.busy": "2020-09-22T22:01:36.223065Z",
     "iopub.status.idle": "2020-09-22T22:01:36.225288Z",
     "shell.execute_reply": "2020-09-22T22:01:36.224811Z"
    },
    "id": "6bpTcDqoLWjY"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Model: \"sequential\"\n",
      "_________________________________________________________________\n",
      "Layer (type)                 Output Shape              Param #   \n",
      "=================================================================\n",
      "dense (Dense)                (None, 12544)             1254400   \n",
      "_________________________________________________________________\n",
      "batch_normalization (BatchNo (None, 12544)             50176     \n",
      "_________________________________________________________________\n",
      "leaky_re_lu (LeakyReLU)      (None, 12544)             0         \n",
      "_________________________________________________________________\n",
      "reshape (Reshape)            (None, 7, 7, 256)         0         \n",
      "_________________________________________________________________\n",
      "conv2d_transpose (Conv2DTran (None, 7, 7, 128)         819200    \n",
      "_________________________________________________________________\n",
      "batch_normalization_1 (Batch (None, 7, 7, 128)         512       \n",
      "_________________________________________________________________\n",
      "leaky_re_lu_1 (LeakyReLU)    (None, 7, 7, 128)         0         \n",
      "_________________________________________________________________\n",
      "conv2d_transpose_1 (Conv2DTr (None, 14, 14, 64)        204800    \n",
      "_________________________________________________________________\n",
      "batch_normalization_2 (Batch (None, 14, 14, 64)        256       \n",
      "_________________________________________________________________\n",
      "leaky_re_lu_2 (LeakyReLU)    (None, 14, 14, 64)        0         \n",
      "_________________________________________________________________\n",
      "conv2d_transpose_2 (Conv2DTr (None, 28, 28, 1)         1600      \n",
      "=================================================================\n",
      "Total params: 2,330,944\n",
      "Trainable params: 2,305,472\n",
      "Non-trainable params: 25,472\n",
      "_________________________________________________________________\n"
     ]
    }
   ],
   "source": [
    "def make_generator_model():\n",
    "    model = tf.keras.Sequential([\n",
    "        layers.Dense(7*7*256, use_bias=False, input_shape=(100,)),\n",
    "        layers.BatchNormalization(),\n",
    "        layers.LeakyReLU(),\n",
    "        \n",
    "        layers.Reshape((7, 7, 256)),\n",
    "        \n",
    "        layers.Conv2DTranspose(128, (5, 5), strides=(1, 1), padding='same', use_bias=False),\n",
    "        layers.BatchNormalization(),\n",
    "        layers.LeakyReLU(),\n",
    "        \n",
    "        layers.Conv2DTranspose(64, (5, 5), strides=(2, 2), padding='same', use_bias=False),\n",
    "        layers.BatchNormalization(),\n",
    "        layers.LeakyReLU(),\n",
    "        \n",
    "        layers.Conv2DTranspose(1, (5, 5), strides=(2, 2), padding='same', use_bias=False, activation='tanh')\n",
    "    ])\n",
    "\n",
    "    return model\n",
    "\n",
    "generator = make_generator_model()\n",
    "generator.summary()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "D0IKnaCtg6WE"
   },
   "source": [
    "### 2. 判别器\n",
    "\n",
    "判别器是一个基于 CNN 的图片分类器。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2020-09-22T22:01:38.361147Z",
     "iopub.status.busy": "2020-09-22T22:01:38.360426Z",
     "iopub.status.idle": "2020-09-22T22:01:38.362716Z",
     "shell.execute_reply": "2020-09-22T22:01:38.362174Z"
    },
    "id": "dw2tPLmk2pEP"
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Model: \"sequential_1\"\n",
      "_________________________________________________________________\n",
      "Layer (type)                 Output Shape              Param #   \n",
      "=================================================================\n",
      "conv2d (Conv2D)              (None, 14, 14, 64)        1664      \n",
      "_________________________________________________________________\n",
      "leaky_re_lu_3 (LeakyReLU)    (None, 14, 14, 64)        0         \n",
      "_________________________________________________________________\n",
      "dropout (Dropout)            (None, 14, 14, 64)        0         \n",
      "_________________________________________________________________\n",
      "conv2d_1 (Conv2D)            (None, 7, 7, 128)         204928    \n",
      "_________________________________________________________________\n",
      "leaky_re_lu_4 (LeakyReLU)    (None, 7, 7, 128)         0         \n",
      "_________________________________________________________________\n",
      "dropout_1 (Dropout)          (None, 7, 7, 128)         0         \n",
      "_________________________________________________________________\n",
      "flatten (Flatten)            (None, 6272)              0         \n",
      "_________________________________________________________________\n",
      "dense_1 (Dense)              (None, 1)                 6273      \n",
      "=================================================================\n",
      "Total params: 212,865\n",
      "Trainable params: 212,865\n",
      "Non-trainable params: 0\n",
      "_________________________________________________________________\n"
     ]
    }
   ],
   "source": [
    "def make_discriminator_model():\n",
    "    model = tf.keras.Sequential([\n",
    "        layers.Conv2D(64, (5, 5), strides=(2, 2), padding='same', input_shape=[28, 28, 1]),\n",
    "        layers.LeakyReLU(),\n",
    "        layers.Dropout(0.3),\n",
    "        \n",
    "        layers.Conv2D(128, (5, 5), strides=(2, 2), padding='same'),\n",
    "        layers.LeakyReLU(),\n",
    "        layers.Dropout(0.3),\n",
    "        \n",
    "        layers.Flatten(),\n",
    "        layers.Dense(1)\n",
    "    ])\n",
    "\n",
    "    return model\n",
    "\n",
    "discriminator = make_discriminator_model()\n",
    "discriminator.summary()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "0FMYgY_mPfTi"
   },
   "source": [
    "## 四、定义损失函数和优化器\n",
    "\n",
    "为两个模型定义损失函数和优化器。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2020-09-22T22:01:38.436353Z",
     "iopub.status.busy": "2020-09-22T22:01:38.435670Z",
     "iopub.status.idle": "2020-09-22T22:01:38.438005Z",
     "shell.execute_reply": "2020-09-22T22:01:38.437468Z"
    },
    "id": "psQfmXxYKU3X"
   },
   "outputs": [],
   "source": [
    "# 该方法返回计算交叉熵损失的辅助函数\n",
    "cross_entropy = tf.keras.losses.BinaryCrossentropy(from_logits=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "PKY_iPSPNWoj"
   },
   "source": [
    "### 1. 判别器损失\n",
    "\n",
    "该方法量化判断真伪图片的能力。它将判别器对真实图片的预测值与值全为 1 的数组进行对比，将判别器对伪造（生成的）图片的预测值与值全为 0 的数组进行对比。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2020-09-22T22:01:38.442883Z",
     "iopub.status.busy": "2020-09-22T22:01:38.442192Z",
     "iopub.status.idle": "2020-09-22T22:01:38.444549Z",
     "shell.execute_reply": "2020-09-22T22:01:38.444040Z"
    },
    "id": "wkMNfBWlT-PV"
   },
   "outputs": [],
   "source": [
    "def discriminator_loss(real_output, fake_output):\n",
    "    real_loss = cross_entropy(tf.ones_like(real_output), real_output)\n",
    "    fake_loss = cross_entropy(tf.zeros_like(fake_output), fake_output)\n",
    "    total_loss = real_loss + fake_loss\n",
    "    return total_loss"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "Jd-3GCUEiKtv"
   },
   "source": [
    "### 2. 生成器损失\n",
    "\n",
    "生成器损失量化其欺骗判别器的能力。直观来讲，如果生成器表现良好，判别器将会把伪造图片判断为真实图片（或 1）。这里我们将把判别器在生成图片上的判断结果与一个值全为 1 的数组进行对比。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2020-09-22T22:01:38.448845Z",
     "iopub.status.busy": "2020-09-22T22:01:38.448175Z",
     "iopub.status.idle": "2020-09-22T22:01:38.450652Z",
     "shell.execute_reply": "2020-09-22T22:01:38.449997Z"
    },
    "id": "90BIcCKcDMxz"
   },
   "outputs": [],
   "source": [
    "def generator_loss(fake_output):\n",
    "    return cross_entropy(tf.ones_like(fake_output), fake_output)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "MgIc7i0th_Iu"
   },
   "source": [
    "由于我们需要分别训练两个网络，判别器和生成器的优化器是不同的。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2020-09-22T22:01:38.455182Z",
     "iopub.status.busy": "2020-09-22T22:01:38.454530Z",
     "iopub.status.idle": "2020-09-22T22:01:38.457018Z",
     "shell.execute_reply": "2020-09-22T22:01:38.456430Z"
    },
    "id": "iWCn_PVdEJZ7"
   },
   "outputs": [],
   "source": [
    "generator_optimizer     = tf.keras.optimizers.Adam(1e-4)\n",
    "discriminator_optimizer = tf.keras.optimizers.Adam(1e-4)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "Rw1fkAczTQYh"
   },
   "source": [
    "## 五、定义训练循环\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2020-09-22T22:01:38.468256Z",
     "iopub.status.busy": "2020-09-22T22:01:38.467626Z",
     "iopub.status.idle": "2020-09-22T22:01:38.470641Z",
     "shell.execute_reply": "2020-09-22T22:01:38.470022Z"
    },
    "id": "NS2GWywBbAWo"
   },
   "outputs": [],
   "source": [
    "EPOCHS = 60\n",
    "noise_dim = 100\n",
    "num_examples_to_generate = 16\n",
    "\n",
    "# 我们将重复使用该种子（在 GIF 中更容易可视化进度）\n",
    "seed = tf.random.normal([num_examples_to_generate, noise_dim])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "jylSonrqSWfi"
   },
   "source": [
    "训练循环在生成器接收到一个随机种子作为输入时开始。该种子用于生产一张图片。判别器随后被用于区分真实图片（选自训练集）和伪造图片（由生成器生成）。针对这里的每一个模型都计算损失函数，并且计算梯度用于更新生成器与判别器。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2020-09-22T22:01:38.477362Z",
     "iopub.status.busy": "2020-09-22T22:01:38.476744Z",
     "iopub.status.idle": "2020-09-22T22:01:38.478614Z",
     "shell.execute_reply": "2020-09-22T22:01:38.479002Z"
    },
    "id": "3t5ibNo05jCB"
   },
   "outputs": [],
   "source": [
    "# 注意 `tf.function` 的使用\n",
    "# 该注解使函数被“编译”\n",
    "@tf.function\n",
    "def train_step(images):\n",
    "    # 生成噪音\n",
    "    noise = tf.random.normal([BATCH_SIZE, noise_dim])\n",
    "\n",
    "    with tf.GradientTape() as gen_tape, tf.GradientTape() as disc_tape:\n",
    "        generated_images = generator(noise, training=True)\n",
    "\n",
    "        real_output = discriminator(images, training=True)\n",
    "        fake_output = discriminator(generated_images, training=True)\n",
    "        \n",
    "        # 计算loss\n",
    "        gen_loss = generator_loss(fake_output)\n",
    "        disc_loss = discriminator_loss(real_output, fake_output)\n",
    "    \n",
    "    #计算梯度\n",
    "    gradients_of_generator = gen_tape.gradient(gen_loss, generator.trainable_variables)\n",
    "    gradients_of_discriminator = disc_tape.gradient(disc_loss, discriminator.trainable_variables)\n",
    "    \n",
    "    #更新模型\n",
    "    generator_optimizer.apply_gradients(zip(gradients_of_generator, generator.trainable_variables))\n",
    "    discriminator_optimizer.apply_gradients(zip(gradients_of_discriminator, discriminator.trainable_variables))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2020-09-22T22:01:38.485024Z",
     "iopub.status.busy": "2020-09-22T22:01:38.484376Z",
     "iopub.status.idle": "2020-09-22T22:01:38.486768Z",
     "shell.execute_reply": "2020-09-22T22:01:38.486194Z"
    },
    "id": "2M7LmLtGEMQJ"
   },
   "outputs": [],
   "source": [
    "def train(dataset, epochs):\n",
    "    for epoch in range(epochs):\n",
    "        start = time.time()\n",
    "\n",
    "        for image_batch in dataset:\n",
    "            train_step(image_batch)\n",
    "\n",
    "        # 实时更新生成的图片\n",
    "        display.clear_output(wait=True)\n",
    "        generate_and_save_images(generator, epoch + 1, seed)\n",
    "\n",
    "        print ('Time for epoch {} is {} sec'.format(epoch + 1, time.time()-start))\n",
    "\n",
    "    # 最后一个 epoch 结束后生成图片\n",
    "    display.clear_output(wait=True)\n",
    "    generate_and_save_images(generator, epochs, seed)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "2aFF7Hk3XdeW"
   },
   "source": [
    "**生成与保存图片**\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2020-09-22T22:01:38.492714Z",
     "iopub.status.busy": "2020-09-22T22:01:38.492075Z",
     "iopub.status.idle": "2020-09-22T22:01:38.494323Z",
     "shell.execute_reply": "2020-09-22T22:01:38.493718Z"
    },
    "id": "RmdVsmvhPxyy"
   },
   "outputs": [],
   "source": [
    "def generate_and_save_images(model, epoch, test_input):\n",
    "    # 注意 training` 设定为 False\n",
    "    # 因此，所有层都在推理模式下运行（batchnorm）。\n",
    "    predictions = model(test_input, training=False)\n",
    "\n",
    "    fig = plt.figure(figsize=(4,4))\n",
    "\n",
    "    for i in range(predictions.shape[0]):\n",
    "        plt.subplot(4, 4, i+1)\n",
    "        plt.imshow(predictions[i, :, :, 0] * 127.5 + 127.5, cmap='gray')\n",
    "        plt.axis('off')\n",
    "\n",
    "    plt.savefig('./images/19/image_at_epoch_{:04d}.png'.format(epoch))\n",
    "    plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "dZrd4CdjR-Fp"
   },
   "source": [
    "## 六、训练模型\n",
    "调用上面定义的 `train()` 方法来同时训练生成器和判别器。在训练之初，生成的图片看起来像是随机噪声。随着训练过程的进行，生成的数字将越来越真实。在大概 50 个 epoch 之后，这些图片看起来像是 MNIST 数字。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`%%time`：将会给出cell的代码运行一次所花费的时间。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 288x288 with 16 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Wall time: 4min 46s\n"
     ]
    }
   ],
   "source": [
    "%%time\n",
    "train(train_dataset, EPOCHS)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "P4M_vIbUi7c0"
   },
   "source": [
    "## 七、创建 GIF\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2020-09-22T22:05:00.796362Z",
     "iopub.status.busy": "2020-09-22T22:05:00.795718Z",
     "iopub.status.idle": "2020-09-22T22:05:00.962623Z",
     "shell.execute_reply": "2020-09-22T22:05:00.961929Z"
    },
    "id": "IGKQgENQ8lEI",
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "GIF动图生成完成！\n"
     ]
    }
   ],
   "source": [
    "import imageio,pathlib\n",
    "\n",
    "def compose_gif():\n",
    "    # 图片地址\n",
    "    data_dir = \"./images/19\"\n",
    "    data_dir = pathlib.Path(data_dir)\n",
    "    paths    = list(data_dir.glob('*'))\n",
    "    \n",
    "    gif_images = []\n",
    "    for path in paths:\n",
    "        gif_images.append(imageio.imread(path))\n",
    "    imageio.mimsave(\"./pic_gif/MINST_DCGAN_19.gif\",gif_images,fps=8)\n",
    "    \n",
    "compose_gif()\n",
    "print(\"GIF动图生成完成！\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "![](./pic_gif/MINST_DCGAN_19.gif)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "id": "k6qC-SbjK0yW"
   },
   "source": [
    "## 八、同系列作品"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "🚀 **深度学习新人必看：**\n",
    "\n",
    "1. [小白入门深度学习 | 第一篇：配置深度学习环境](https://mtyjkh.blog.csdn.net/article/details/118575238)\n",
    "2. [小白入门深度学习 | 第二篇：编译器的使用-Jupyter Notebook](https://mtyjkh.blog.csdn.net/article/details/118814364)\n",
    "3. [小白入门深度学习 | 第三篇：深度学习初体验](https://mtyjkh.blog.csdn.net/article/details/119081309)"
   ]
  }
 ],
 "metadata": {
  "accelerator": "GPU",
  "colab": {
   "collapsed_sections": [],
   "name": "dcgan.ipynb",
   "toc_visible": true
  },
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.8rc1"
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": false,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {
    "height": "calc(100% - 180px)",
    "left": "10px",
    "top": "150px",
    "width": "221.273px"
   },
   "toc_section_display": true,
   "toc_window_display": true
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
